// http://www.kkh86.com/it/chrome-extension-doc/extensions/runtime.html
var sockets = []

// 已经加入的房间
var rooms = {}

function getMyLocalIP (mCallback) {
  var all_ip = [];

  var RTCPeerConnection = window.RTCPeerConnection ||
    window.webkitRTCPeerConnection || window.mozRTCPeerConnection;

  var pc = new RTCPeerConnection({
    iceServers: []
  });

  pc.createDataChannel('');

  pc.onicecandidate = function (e) {

    if (!e.candidate) {
      mCallback(all_ip);
      return;
    }
    var ip = /^candidate:.+ (\S+) \d+ typ/.exec(e.candidate.candidate)[1];
    if (all_ip.indexOf(ip) == -1)
      all_ip.push(ip);
  };
  pc.createOffer(function (sdp) {
    pc.setLocalDescription(sdp);
  }, function onerror () { });
}

var socketOptions = {
  // host: '192.168.124.8',
  // host: '10.2.2.36',
  host: '',
  port: 8200,
  path: '/enkel',
  room: '/public'
}

var fp = ''

function __loadJS (url) {
  return new Promise((resolve) => {
    var script = document.createElement('script')
    script.type = "text/javascript"
    if (script.readyState) {
      script.onreadystatechange = function () {
        if (script.readyState == "loaded" || script.readyState == "complete") {
          script.onreadystatechange = null
          resolve(true)
        }
      }
    } else {
      script.onload = function () {
        resolve(true)
      }
    }
    script.src = url
    document.body.appendChild(script)
  })
}

function loadJS (scripts) {
  return new Promise(async (resolve) => {
    if (!scripts || (scripts.length == 0)) return resolve(true)
    if (Object.prototype.toString.call(scripts) == '[object String]') {
      await __loadJS(scripts)
      return resolve(true)
    }
    var _scripts = []
    for (var i = 0; i < scripts.length; i++) {
      _scripts.push(__loadJS(scripts[i]))
    }
    await Promise.all(_scripts)
    return resolve(true)
  })
}

function _getEntitySender (id) {
  return {
    id: id || fp,
    name: 'Extension',
    fp: fp
  }
}

var ActionType = {
  connect: '1',
  confirm: '2',
  disconnect: '3',
  joinRoom: '4',
  exitRoom: '5',
  sendUserScript: '101',
  setTabActive: '102',
  refreshTab: '103',
  getAllStorageScripts: "104",
  settingUserScript: "105",
  closeTab: "106",
  getTabsByWindowId: '107',
  openNewTab: '108',
  getTabInfo: '109',
  getAllWindow: '201',
  setWindowActive: '202'
}

function _getEntityMessage (actionType, data = {}) {
  return {
    action: ActionType[actionType],
    data
  }
}

function _getScriptString (url) {
  return `if (document.querySelector("#append_us_url")) {
    document.getElementsByTagName("body")[0].removeChild(document.querySelector('#append_us_url'))
  }
  var script = document.createElement("script")
  script.id = "append_us_url"
  script.type = "text/javascript"
  script.src = "${url}";
  document.body.appendChild(script)`;
}

function _msgHandler (msg = {}, ack = () => { }) {
  // if (socketId == msg.from?.id) return
  var _sender = msg.from || {}
  var _message = msg.data || {}
  var _config = msg.config || {}
  var _action = _config.action
  switch (_action) {
    case ActionType.connect:
      console.log(`${_sender.id}[${_sender.name}] 扫码进入了`)
      break
    case ActionType.disconnect:
      console.log(`${_sender.id}[${_sender.name}] 退出了`)
      break
    case ActionType.confirm:
      break
    case ActionType.sendUserScript:
      chrome.tabs.sendMessage(Number(_config.tabId), _message, (r) => {
        if (!r) {
          // tab 无响应，则直接注入脚本
          let _script = '';
          if (_message.url) {
            _script = _getScriptString(_message.url)
          } else {
            _script = _message.script
          }
          chrome.tabs.executeScript(Number(_config.tabId), {
            code: _script
          })
        }
      })

      if (_message.cache) {
        chrome.tabs.get(Number(_config.tabId), (tab) => {
          let _key = tab.url.split('?')[0].split('//').pop().split('/')[0]
          chrome.storage.sync.get(_key, (res) => {
            let _o = res
            if (!res || Object.keys(res).length < 1) {
              _o[_key] = [{
                url: _message.url,
                name: _message.name,
                desc: _message.desc,
                author: _message.author,
                active: true,
              }]
            } else {
              if (Object.prototype.toString.call(_o[_key]) == '[object String]') {
                _o[_key] = [_o[_key], {
                  url: _message.url,
                  active: true,
                  name: _message.name,
                  desc: _message.desc,
                  author: _message.author,
                }]
              } else {
                if (!_o[_key].some(itm => (itm.url == _message.url))) {
                  _o[_key].push({
                    url: _message.url,
                    active: true,
                    name: _message.name,
                    desc: _message.desc,
                    author: _message.author,
                  })
                }
              }
            }
            chrome.storage.sync.set(_o, () => { })
          })
        })
      }
      break
    case ActionType.setTabActive:
      chrome.windows.update(Number(_config.winId), {
        focused: true,
      })
      chrome.tabs.update(Number(_config.tabId), {
        selected: true,
      })
      break
    case ActionType.refreshTab:
      chrome.windows.update(Number(_config.winId), {
        focused: true,
      })
      chrome.tabs.update(Number(_config.tabId), {
        selected: true,
      })
      chrome.tabs.executeScript(Number(_config.tabId), {
        code: 'location.reload()'
      })
      break
    case ActionType.getAllStorageScripts:
      if (_message.key) {
        chrome.storage.sync.get(_message.key, (item) => {
          socket.emit('to-client', {
            from: {
              id: socket.id,
              fp: fp,
              name: 'Extension',
              avatar: ''
            },
            config: msg.config || {},
            to: {
              id: msg.from?.id
            },
            data: {
              key: _message.key,
              items: item[_message.key] || []
            }
          })
        })
      }
      break;
    case ActionType.settingUserScript:
      // 编辑脚本
      if (!_message.key) return
      let _action = _message.action
      switch (_action) {
        case 'remove':
          // 删除脚本
          chrome.storage.sync.get(_message.key, (item) => {
            if (item[_message.key]) {
              let _data = item[_message.key]
              _data = _data.filter(itm => itm.url != _message.url)
              chrome.storage.sync.set({
                [_message.key]: _data
              }, () => {
                // 删除成功
                socket.emit('to-client', {
                  from: {
                    id: socket.id,
                    fp: fp,
                    name: 'Extension',
                    avatar: ''
                  },
                  config: msg.config || {},
                  to: {
                    id: msg.from?.id
                  },
                  data: {
                    key: _message.key,
                    items: _data || []
                  }
                })
              })
            }
          })
          break
        case 'edit':
          // 编辑脚本状态
          chrome.storage.sync.get(_message.key, (item) => {
            if (item[_message.key]) {
              let _data = item[_message.key]
              _data = _data.map(itm => {
                if (itm.url == _message.url) {
                  itm.active = _message.active
                }
                return itm
              })
              chrome.storage.sync.set({
                [_message.key]: _data
              }, () => {
                // 修改成功
                socket.emit('to-client', {
                  from: {
                    id: socket.id,
                    fp: fp,
                    name: 'Extension',
                    avatar: ''
                  },
                  config: msg.config || {},
                  to: {
                    id: msg.from?.id
                  },
                  data: {
                    key: _message.key,
                    items: _data || []
                  }
                })
              })
            }
          })
          break
      }
      break;
    case ActionType.closeTab:
      chrome.tabs.remove(Number(_config.tabId), () => {
        if (ack) {
          ack({
            status: 200,
            tabId: _config.tabId,
            message: '成功'
          })
        }
      })
      break
    case ActionType.getTabsByWindowId:

      if (ack) {
        chrome.tabs.getAllInWindow(Number(_config.winId), (tabs) => {
          ack({
            tabs: tabs || []
          })
        })
      }
      break
    case ActionType.openNewTab:
      chrome.tabs.create({
        windowId: Number(_config.winId),
        url: _message.url || '',
        selected: true,
      }, (tab) => {

        if (ack) {
          tab.url = _message.url
          tab.title = _message.url
          ack({
            tab: tab,
          })
        }
      })
      break
    case ActionType.getTabInfo:
      chrome.tabs.get(Number(_config.tabId), (tab) => {
        if (ack) {
          ack({
            tab: tab,
          })
        }
      })
      break
    case ActionType.getAllWindow:
      chrome.windows.getAll({
        populate: true,
      }, (windows) => {
        socket.emit('to-client', {
          from: {
            id: socket.id,
            fp: fp,
            name: 'Extension',
            avatar: ''
          },
          config: msg.config || {},
          to: {
            id: msg.from?.id
          },
          data: {
            windows: windows
          }
        })
      })
      break
    case ActionType.setWindowActive:
      if (_config.winId) {
        chrome.windows.update(Number(_config.winId), {
          focused: true,
        })
      }
      break
    case ActionType.joinRoom:
      // joinRoom()
      break
    case ActionType.exitRoom:
      // joinRoom()
      break
  }
}

var socket;

function initSocket () {
  return new Promise((resolve) => {
    if (socket) {
      socket.disconnect();
    }
    socket = io(`http://${socketOptions.host}:${socketOptions.port}`, {
      path: socketOptions.path || '/enkel',
      transports: ['websocket']
    });//和服务器建立连接

    socket.on('connect', (_) => {

      socket.on('to-client', function (msg, ack) {
        _msgHandler(msg)
      })
      socket.on('to-client-with-ack', function (msg, ack) {
        _msgHandler(msg, ack)
      })

      socket.on('to-room', (msg) => { })

      socket.on('to-all', (msg) => { })

      socket.on('from-server', (msg) => {
        console.log('【from-server】:', msg)
      })

      resolve(true)
    })

    socket.on('disconnect', () => {
      sockets = []
    })
  })
}

function joinRoom (data = {}) {
  socket.emit('enter', {
    from: Object.assign({
      id: socket.id,
      fp: fp,
      name: 'Extension',
      avatar: ''
    }, data.from || {}),
    config: Object.assign({
      room: '',
      tabId: '',
      winId: ''
    }, data.config || {}),
    data: Object.assign({}, data.data || {})
  })
}

function leaveRoom (data = {}) {
  socket.emti('leave', {
    from: Object.assign({
      id: socket.id,
      fp: fp,
      name: 'Extension',
      avatar: ''
    }, data.from || {}),
    config: Object.assign({
      room: '',
      tabId: '',
      winId: ''
    }, data.config || {}),
    data: Object.assign({}, data.data || {})
  })
}

loadJS(['https://cdn.socket.io/4.3.2/socket.io.js', 'https://cdn.jsdelivr.net/npm/@fingerprintjs/fingerprintjs@3/dist/fp.min.js']).then(async () => {
  if (!fp) {
    await FingerprintJS.load({ token: 'your-browser-token' }).then(f => f.get()).then(result => {
      fp = result.visitorId.substring(0, 8)
      // resetSocketOptions({
      //   room: '/' + fp
      // })
    })
  }
  if (sockets.length == 0) {
    getMyLocalIP(ips => {
      socketOptions.host = ips.join('\n ')
      initSocket()
    })

  }
})

function resetSocketOptions (params = {}) {
  return new Promise(async (resolve) => {
    if (Object.keys(params).length > 0) {
      socketOptions = Object.assign({}, socketOptions, params)
      await initSocket()
    }
    resolve(true)
  })

}

window.addEventListener('online', (e) => {
  getMyLocalIP(ips => {
    socketOptions.host = ips.join('\n ')
    initSocket()
  })
});

window.addEventListener('offline', (e) => {
  socket.dispose()
  sockets = []
});

chrome.runtime.onSuspend.addListener(function () {
  // 应用运行时环境在卸载前会向事件页面发送 onSuspend() 事件，您的事件页面可以监听该事件并在应用关闭前做清理任务。
  socket.dispose()
})

// chrome.runtime.onInstalled.addListener((details) => {
//   console.log('>>>> onInstalled: ', details)
// })

// chrome.runtime.onRestartRequired.addListener((details) => {
//   console.log('>>>> onRestartRequired: ', details)
// })
